/** * 该代码用于描述产品的结构信息 */
<template>
  <div style="position: relative; height: calc(70vh)">
    <div class="header">
      <button class="back-button" @click="back">返回</button>
      <span class="title">材料结构展示 / {{ rootname }}</span>
    </div>
    <!-- 主内容区域，分为左侧的侧边栏和右侧的主工作区 -->
    <div class="content" style="display: flex; height: 100%; overflow: hidden">
      <!-- 左侧侧边栏 -->
      <aside class="sidebar">
        <div v-for="item in listedproductNames" :key="item.productId" class="memo-item">
          <div class="memo-content">
            <div class="memo-status">{{ item.productName }}</div>
            <button class="memo-button">切换展示</button>
          </div>
        </div>
      </aside>

      <!-- 右侧主工作区 -->
      <div class="flow-container">
        <Structure_Information ref="InformationWindowRef"></Structure_Information>

        <VueFlow
          v-model:nodes="nodes"
          v-model:edges="edges"
          fit-view-on-init
          class="confirm-flow"
          :default-zoom="1.5"
          :min-zoom="0.2"
          :max-zoom="4"
          @node-click="onNodeClick"
          @pane-click="clearSelection"
          @before-connect="onBeforeConnect"
        >
          <Background color="white" />
          <!-- 节点模板 -->
          <template #node-productNode_homeMade="props">
            <productNode_homeMade :id="props.id" :data="props.data" @toolbar-action="handleToolbarAction" />
          </template>
          <template #node-productNode_outBuy="props">
            <productNode_outBuy :id="props.id" :data="props.data" @toolbar-action="handleToolbarAction" />
          </template>
          <template #node-productNode_outBuy1="props">
            <productNode_outBuy1 :id="props.id" :data="props.data" @toolbar-action="handleToolbarAction" />
          </template>
        </VueFlow>
      </div>
    </div>
  </div>
</template>

<script lang="ts" setup>
import { onMounted, ref } from "vue";
import { VueFlow, type Node, type Edge, MarkerType } from "@vue-flow/core";
import { Background } from "@vue-flow/background";
import { ProductTree } from "@/api/interface";
import { computed } from "vue";
import { useRoute } from "vue-router";
import { useTabsStore } from "@/stores/modules/tabs";
import productNode_homeMade from "@/views/proTable/components/productNode_homeMade.vue";
import productNode_outBuy from "@/views/proTable/components/productNode_outBuy.vue";
import productNode_outBuy1 from "@/views/proTable/components/productNode_outbuy1.vue";
import Structure_Information from "./components/structure_Information.vue";
import { ElMessage } from "element-plus";
import { calculateNodeCoordinates, assignNodeIndices } from "@/utils/nodePositionHandler";
import axios from "axios";
const route = useRoute();
/**当前分析的材料id */
const materialId = route.params.id as string;
/** 存储有对应材料的产品号码 */
const listedproductNames = ref<Array<{ productId: number; productName: string }>>([]);
// 对应分析的材料信息
const rootMaterial = ref();
/**当前展示的结构树 */
const tree = ref<Partial<ProductTree.ResProduct_Tree>>();
// type TreeType = typeof tree;
/**产品名称 */
const rootname = computed(() => rootMaterial.value?.materialName);
const baseUrl = import.meta.env.VITE_BASE_URL;
/**当前分析的产品id */
const productId = ref("-1");
const nodes = ref<Node[]>([]);
const edges = ref<Edge[]>([]);

const InformationWindowRef = ref<InstanceType<typeof Structure_Information> | null>(null);
const tabStore = useTabsStore();
/**节点和其坐标 */
const nodeCoordinates = ref<ProductTree.NodeLocation[]>([]);
/**节点序号与materialId的映射关系 */
const indexToNodeMap = ref<Map<number, number>>(new Map());
/**以节点序号的边描述 */
const indexedEdges = ref<{ source: number; target: number }[]>([]);
const selectedMaterialId = ref<number | null>(null);

onMounted(async () => {
  await initFormData();
  initializeNodesAndEdges();
});

/**获取产品结构树信息 */
const initFormData = async () => {
  try {
    const userInfo = JSON.parse(localStorage.getItem("userInfo") || "{}");
    const userId = Number(userInfo.id) || 0; // 如果没有 id，则使用默认值 0
    // 获取对应有多少产品的信息
    let response = await axios.get(baseUrl + "/api/carbon/getProductInfosByMaterialId?materialId=" + materialId);
    if (response.data && response.data.code === 200) {
      listedproductNames.value = response.data.data;
    } else {
      // 处理后端返回的错误信息
      const errorMsg = response.data.msg || "获取产品信息失败";
      console.error("获取产品信息错误:", errorMsg);
      ElMessage.error(errorMsg);
    }
    // 获取材料详细信息
    response = await axios.post(baseUrl + "/api/carbon/getMaterialById?materialId=" + materialId, {
      userId: userId
    });
    if (response.data && response.data.code === 200) {
      rootMaterial.value = response.data.data;
    } else {
      // 处理后端返回的错误信息
      const errorMsg = response.data.msg || "获取产品id信息失败";
      console.error("获取产品id信息错误:", errorMsg);
      ElMessage.error(errorMsg);
    }
    if (!listedproductNames.value || listedproductNames.value.length === 0) {
      ElMessage.error("没有找到对应的材料信息，请检查材料id是否正确");
      return;
    }
    const firstKeyNum = listedproductNames.value[0].productId;
    response = await axios.post(baseUrl + "/api/carbon/getMaterialTree?productId=" + firstKeyNum + "&materialId=" + materialId, {
      userId: userId
    });
    if (response.data && response.data.code === 200) {
      tree.value = response.data.data;
    } else {
      // 处理后端返回的错误信息
      const errorMsg = response.data.msg || "获取产品结构树失败";
      console.error("获取产品结构树错误:", errorMsg);
      ElMessage.error(errorMsg);
    }
  } catch (error) {
    console.error("数据获取出错:", error);
    ElMessage.error("数据获取出错，可能是因为参数错误或网络问题");
  }
};

const onBeforeConnect = () => {
  // 阻止所有连线
  return false;
};

/**
 * 清除选中状态
 */
const clearSelection = () => {
  selectedMaterialId.value = null;
  nodes.value.forEach(node => {
    if (node.data) {
      node.style = { ...node.style, background: "#fff" };
    }
  });
  nodes.value = [...nodes.value];
};

/**返回主界面 */
const back = () => {
  // 判断该标签页是否固定
  if (route.meta.isAffix) return;
  tabStore.removeTabs(route.fullPath);
};

/**
 * 节点点击事件
 * @param node 点击节点内容
 */
function onNodeClick(node: any) {
  console.log(node);
}

/**
 * 初始化节点和连线
 */
const initializeNodesAndEdges = () => {
  // 注册树中提到的所有材料
  if (!tree.value || !tree.value.node || !tree.value.edge) {
    ElMessage({
      type: "warning",
      message: "产品树为空!"
    });
    return;
  }
  // 处理特殊情况：只有根节点，没有边
  if (tree.value.edge.length === 0) {
    // 创建单独的根节点
    nodes.value = [
      {
        id: "1",
        position: { x: 0, y: 0 },
        data: {
          selected: false,
          materialID: -1,
          label: rootname.value,
          rootid: productId.value
        },
        style: {
          background: "#fff"
        },
        type: "productNode_outBuy"
      }
    ];
    edges.value = []; // 边为空数组
    return; // 提前返回，不执行后续逻辑
  }
  const result = assignNodeIndices(tree.value.edge);
  indexToNodeMap.value = result.indexToNodeMap;
  indexedEdges.value = result.indexedEdges;
  nodeCoordinates.value = calculateNodeCoordinates(indexedEdges.value, 1, 300, 80);
  // 添加节点
  const newNodes: (Node & { selected?: boolean })[] =
    nodeCoordinates.value.map(unitnode => {
      const materialID = indexToNodeMap.value.get(unitnode.index);
      // 没找到，则产品节点
      if (materialID === -1) {
        return {
          id: String(unitnode.index),
          position: { x: unitnode.x, y: unitnode.y }, // 节点垂直排列
          data: {
            selected: false,
            materialID: -1,
            label: rootname.value,
            rootid: productId.value
          },
          style: {
            background: "#fff"
          },
          type: "productNode_outBuy"
        };
      } else {
        const material = findMaterialInfoById(materialID)!;
        let nodeType = "";
        if (material.sourceType === 1) nodeType = "productNode_homeMade";
        else nodeType = "productNode_outBuy1";
        return {
          id: String(unitnode.index),
          position: { x: unitnode.x, y: unitnode.y }, // 节点垂直排列
          data: {
            selected: false,
            materialID: materialID,
            label: material.materialName
          },
          style: {
            background: "#fff"
          },
          type: nodeType
        };
      }
    }) || [];
  nodes.value = newNodes; // 更新节点
  // 添加边
  const newEdges: Edge[] =
    indexedEdges.value.map((unitnode, index) => {
      return {
        id: (index + 1).toString(),
        source: unitnode.source.toString(),
        target: unitnode.target.toString(),
        type: "button",
        markerEnd: {
          type: MarkerType.ArrowClosed,
          color: "#999999"
        }
      };
    }) || [];
  // 更新 edges.value
  edges.value = newEdges;
};

/**
 * 返回材料在tree.value.node中的信息
 * @param id 材料id
 */
function findMaterialInfoById(id: number | undefined) {
  if (id === undefined) return undefined;
  if (!tree.value || !tree.value.node) return undefined;
  return tree.value.node.find(material => material.id === id);
}

const openInformWindow = (nodeid: string, source: number) => {
  if (InformationWindowRef.value) {
    InformationWindowRef.value.openDialog(nodeid, source);
  }
};

/**
 * 按下toolBar按钮的处理函数
 */
const handleToolbarAction = (action: string, materialId: string, source: number) => {
  openInformWindow(materialId, source);
};
</script>

<style>
.content {
  display: flex;
  height: 100%;
  overflow: hidden;
}

.sidebar {
  box-sizing: border-box;
  display: flex;
  flex-direction: column;
  gap: 15px;
  width: 18%;
  min-width: 180px;
  max-width: 300px;
  padding: 20px;
  overflow-y: auto;
  background-color: #f4f6f8;
  border-right: 1px solid #e0e0e0;
  border-radius: 8px;
  box-shadow: 0 2px 10px rgb(0 0 0 / 10%);
}

.sidebar .memo-item {
  padding: 12px 16px;
  margin-bottom: 3px;
  cursor: pointer;
  background-color: #ffffff;
  border: 1px solid #dddddd;
  border-radius: 8px;
  box-shadow: 0 2px 5px rgb(0 0 0 / 10%);
  transition: background-color 0.3s;
}

.sidebar .memo-item:hover {
  background-color: #e6f5f3;
}

.sidebar .memo-name {
  margin-bottom: 10px;
  font-size: 16px;
  font-weight: bold;
}

.sidebar .memo-content {
  display: flex;
  align-items: center;
  justify-content: space-between;
}

.sidebar .memo-status {
  flex: 1;
  padding-right: 10px;
  font-size: 14px;
}

.sidebar .memo-button {
  padding: 6px 12px;
  color: white;
  cursor: pointer;
  background-color: #009688;
  border: none;
  border-radius: 5px;
  transition: background-color 0.3s;
}

.sidebar .memo-button:hover {
  background-color: #007d6a;
}
/* 选中材料项的样式 */
.memo-item-selected {
  background-color: #b2dfdb !important; /* 改为更浅的绿色 */
  border-left: 4px solid #009688; /* 保持深绿色边框作为高亮指示 */
  transform: translateX(15px);
  /* 移除文字颜色修改，保持原来的黑色文字以提高可读性 */
}

/* 确保选中效果优先级高于悬停效果 */
.sidebar .memo-item-selected:hover {
  background-color: #b2dfdb !important; /* 鼠标悬停时保持相同的浅色 */
}

.sidebar-tabs {
  display: flex;
  margin-bottom: 15px;
  border-bottom: 1px solid #e0e0e0;
}

.sidebar-tab {
  flex: 1;
  padding: 8px 0;
  margin: 0;
  font-size: 14px;
  color: #555;
  cursor: pointer;
  background-color: transparent;
  border: none;
  border-bottom: 2px solid transparent;
  border-radius: 0;
  transition: all 0.3s ease;
}

.sidebar-tab:hover {
  color: #009688;
  background-color: transparent;
}

.sidebar-tab.active {
  color: #009688;
  font-weight: bold;
  background-color: transparent;
  border-bottom: 2px solid #009688;
}

.sidebar-content {
  display: flex;
  flex-direction: column;
  gap: 15px;
  overflow-y: auto;
}

.flow-container {
  position: relative;
  flex: 1;
  overflow: hidden;
}
.header {
  display: flex;
  align-items: center;
  padding: 10px 20px;
  background-color: #ffffff;
  border-bottom: 1px solid #dddddd;
  border-radius: 8px;
}
.header-buttons {
  display: flex;
  gap: 10px; /* 按钮之间的间距 */
  margin-left: auto; /* 将按钮推到最右侧 */
}
.back-button {
  padding: 8px 12px;
  margin-right: 20px;
  font-size: 14px;
  color: white;
  cursor: pointer;
  background-color: #009688;
  border: none;
  border-radius: 4px;
  transition: background-color 0.2s ease;
}
.back-button:hover {
  background-color: #007d6a;
}
.title {
  font-size: 18px;
  font-weight: bold;
  color: #333333;
}
.modal {
  position: fixed;
  top: 0;
  left: 0;
  z-index: 1000;
  display: flex;
  align-items: center;
  justify-content: center;
  width: 100%;
  height: 100%;
  background: rgb(0 0 0 / 50%);
}
.modal-content {
  z-index: 9999;
  width: 400px;
  max-width: 90%;
  padding: 20px;
  background-color: white;
  border-radius: 8px;
  box-shadow: 0 2px 10px rgb(0 0 0 / 10%);
}
select {
  z-index: 10000;
  width: 100%;
  padding: 8px;
  margin: 10px 0;
  border: 1px solid #cccccc;
  border-radius: 4px;
}
button {
  padding: 8px 12px;
  margin: 5px;
  color: white;
  cursor: pointer;
  background-color: #009688;
  border: none;
  border-radius: 4px;
}
button:hover {
  background-color: #009688;
}
.customNode {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 100px;
  height: 50px;
  cursor: pointer;
  border: 1px solid #cccccc;
  border-radius: 4px;
}
.customNode.selected {
  color: white;
  background-color: #4caf50;
}
.vue-flow__node-toolbar {
  display: flex;
  gap: 0.5rem;
  align-items: center;
  padding: 8px;
  background-color: #2d3748;
  border-radius: 8px;
  box-shadow: 0 0 10px rgb(0 0 0 / 50%);
}
.vue-flow__node-toolbar button {
  padding: 0.5rem;
  color: white;
  cursor: pointer;
  background: #4a5568;
  border: none;
  border-radius: 8px;
}
.vue-flow__node-toolbar button.selected {
  background: #009688;
}
.vue-flow__node-toolbar button:hover {
  background: #009688;
}
.vue-flow__node-productNode_homeMade {
  padding: 20px 24px;
  color: #009688;
  background: #e6f5f3;
  border: 1px solid #009688;
  border-radius: 4px;
  box-shadow: 0 0 10px rgb(0 0 0 / 20%);
}
.vue-flow__node-productNode_homeMade.selected {
  border: 1px solid red;
}
.vue-flow__node-productNode_outBuy {
  padding: 20px 24px;
  color: #009688;
  background: #e6f5f3;
  border: 1px solid #009688;
  border-radius: 4px;
  box-shadow: 0 0 10px rgb(0 0 0 / 20%);
}
.vue-flow__node-productNode_outBuy.selected {
  border: 1px solid red;
}
.vue-flow__node-productNode_outBuy1 {
  padding: 20px 24px;
  color: #009688;
  background: #e6f5f3;
  border: 1px solid #009688;
  border-radius: 4px;
  box-shadow: 0 0 10px rgb(0 0 0 / 20%);
}
.vue-flow__node-productNode_outBuy1.selected {
  border: 1px solid red;
}
.vue-flow__handle {
  pointer-events: none !important;
}
</style>
